﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OxyPlot;

namespace AutoCorrelatorGUI.Model
{
   public class WellStats
   {
      public double Mean { get; set; }
      public double StdError { get; set; }
      public double Median { get; set; }
      public double Mode { get; set; }
      public double StdDev { get; set; }
      public double Variance { get; set; }
      public double Kurtosis { get; set; }
      public double Skewness { get; set; }
      public double Range { get; set; }
      public double Minimum { get; set; }
      public double Maximum { get; set; }
      public double Sum { get; set; }
      public int Count { get; set; }
      public double Norm { get; set; }

      public void Calc(IList<DataPoint> values)
      {
         //Reset statistics
         Mean = 0.0;
         StdError = 0.0;
         Median = 0.0;
         Mode = 0.0;
         StdDev = 0.0;
         Variance = 0.0;
         Kurtosis = 0.0;
         Skewness = 0.0;
         Range = 0.0;
         Minimum = double.MaxValue;
         Maximum = double.MinValue;
         Sum = 0.0;
         Count = values.Count;
         Norm = 0.0;

         if (Count == 0)
            return;

         double dCount = (double)Count;
         var sorted = values.OrderByDescending(g => g.Y);

         //Finally, calculate the statistics on the auto correlated data
         for (int i = 0; i < values.Count; i++)
         {
            //Maximum = Math.Max(Maximum, values[i].Y);
            //Minimum = Math.Min(Minimum, values[i].Y);

            Sum += values[i].Y;
            Norm += values[i].Y * values[i].Y;
         }

         Maximum = sorted.First().Y;
         Minimum = sorted.Last().Y;

         Range = Maximum - Minimum;
         Mean = Sum / dCount;
         Norm = Math.Sqrt(Norm);

         //Last one is the standard deviation
         for (int i = 0; i < values.Count; i++)
         {
            double diff = values[i].Y - Mean;

            diff *= diff;
            Variance += diff;
            diff *= diff;
            Skewness += diff;
            diff *= diff;
            Kurtosis += diff;
         }

         Variance /= dCount - 1.0;
         StdDev = Math.Sqrt(Variance);
         StdError = StdDev / Math.Sqrt(dCount);

         Skewness = ((dCount) / (StdDev * StdDev * StdDev * (dCount - 1) * (dCount - 2))) * Skewness;
         Kurtosis = (((dCount * (dCount + 1.0)) / (Math.Pow(StdDev, 4.0) * (dCount - 1.0) * (dCount - 2.0) * (dCount - 3.0))) * Kurtosis) - ((3.0 * (dCount - 1.0) * (dCount - 1.0)) / ((dCount - 2.0) * (dCount - 3.0)));

         int mid = Count / 2;

         if (Count % 2 > 0)
         {
            //We are odd, should be easy
            Median = sorted.ElementAt(mid).Y;
         }
         else
         {
            Median = (sorted.ElementAt(mid).Y + sorted.ElementAt(mid + 1).Y) / 2.0;
         }

         Mode = values.GroupBy(v => v)
                      .OrderByDescending(g => g.Count())
                      .First()
                      .Key.Y;



      }
   }
}
